package com.jq.jqaicode.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jq.jqaicode.ai.AiCodeService;
import com.jq.jqaicode.common.ResultUtils;
import com.jq.jqaicode.config.ThreadPoolConfig;
import com.jq.jqaicode.common.file.CodeParserSaveExecutor;
import com.jq.jqaicode.event.GenHtmlScreenshotEvent;
import com.jq.jqaicode.mapper.AiAppMapper;
import com.jq.jqaicode.model.entity.AiApp;
import com.jq.jqaicode.model.enums.ChatHistoryMessageTypeEnum;
import com.jq.jqaicode.model.enums.CodeGenTypeEnum;
import com.jq.jqaicode.service.AiAppService;
import com.jq.jqaicode.service.AiChatHistoryService;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.bsc.langgraph4j.CompiledGraph;
import org.bsc.langgraph4j.prebuilt.MessagesState;
import org.bsc.langgraph4j.streaming.StreamingOutput;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;

import java.util.*;

@Service
@Slf4j
public class AiAppServiceImpl extends ServiceImpl<AiAppMapper, AiApp> implements AiAppService {

    @Autowired
    AiCodeService aiCodeService;
    @Autowired
    AiChatHistoryService aiChatHistoryService;
    @Autowired
    ApplicationEventPublisher applicationEventPublisher;
    @Resource
    CompiledGraph<MessagesState<ChatMessage>> workflow;
    @Autowired
    @Qualifier(ThreadPoolConfig.DEFAULT_EXECUTOR)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public Flux<String> chatToGenCode(String appId, String message) {
        // 1. 参数校验
        if(StrUtil.isBlank(appId)){
            ResultUtils.runError("应用id不能为空");
        }
        if(StrUtil.isBlank(message)){
            ResultUtils.runError("消息内容不能为空");
        }
        // 2. 查询应用信息
        AiApp aiApp = this.getById(appId);
        if(aiApp==null){
            ResultUtils.runError("查询应用不存在");
        }
        // 3. 在调用 AI 前，先保存用户消息到数据库中
        aiChatHistoryService.addChatMessage(appId, message, ChatHistoryMessageTypeEnum.USER.getValue(),  aiApp.getAddUser());
        try {
            // 4. 调用 AI 生成代码（流式）
            Flux<String> contentFlux = aiCodeService.generateHtmlCodeStream(appId,message);
            // 5. 收集 AI 响应的内容，并且在完成后保存记录到对话历史+保存成文件
            StringBuilder aiResponseBuilder = new StringBuilder();
            return contentFlux.map(chunk -> {
                // 实时收集 AI 响应的内容
                aiResponseBuilder.append(chunk);
                return chunk;
            }).doOnComplete(() -> {
                // 流式返回完成后，保存 AI 消息到文件+对话历史表中
                String aiResponse = aiResponseBuilder.toString();
                CodeParserSaveExecutor.executeParser(appId, aiResponse, CodeGenTypeEnum.HTML);
                log.info("保存成功");
                aiChatHistoryService.addChatMessage(appId, aiResponse, ChatHistoryMessageTypeEnum.AI.getValue(),  aiApp.getAddUser());
            }).doOnError(error -> {
                // 如果 AI 回复失败，也需要保存记录到数据库中
                String errorMessage = "AI 回复失败：" + error.getMessage();
                aiChatHistoryService.addChatMessage(appId, errorMessage, ChatHistoryMessageTypeEnum.AI.getValue(),  aiApp.getAddUser());
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
            return Flux.just(e.getMessage());
        }
    }

    @Override
    public Flux<String> workflowGenCode(String appId, String message){
        // 1. 参数校验
        if(StrUtil.isBlank(appId)){
            ResultUtils.runError("应用id不能为空");
        }
        if(StrUtil.isBlank(message)){
            ResultUtils.runError("消息内容不能为空");
        }
        // 2. 查询应用信息
        AiApp aiApp = this.getById(appId);
        if(aiApp==null){
            ResultUtils.runError("查询应用不存在");
        }

        //消息列表
        List<ChatMessage> chatMessageList = aiChatHistoryService.loadHistory(appId);
        List<ChatMessage> messages = new ArrayList<>();
        //2.历史记忆
        messages.addAll(chatMessageList);
        //3.新用户输入词
        messages.add(new UserMessage(appId,message));

        aiChatHistoryService.addChatMessage(appId, message, ChatHistoryMessageTypeEnum.USER.getValue(), aiApp.getAddUser());
        try {
            return Flux.create(sink -> {
                // 用线程池代替 new Thread 更安全生产
                StringBuilder aiReplyBuilder = new StringBuilder();
                threadPoolTaskExecutor.submit(() -> {
                    try {
                        for (var out : workflow.stream(Map.of("messages", messages))) {
                            if (out instanceof StreamingOutput streaming) {
                                sink.next(String.valueOf(streaming.chunk()));
                                aiReplyBuilder.append(String.valueOf(streaming.chunk()));
                            }else {
                                log.info( "{}", out );
                            }
                        }
                        sink.complete();
                        // ⚠ 流结束后再保存AI历史
                        String aiReply = aiReplyBuilder.toString();
                        aiChatHistoryService.addChatMessage(appId, aiReply, ChatHistoryMessageTypeEnum.AI.getValue(), "1");
                    } catch (Exception e) {
                        e.printStackTrace();
                        sink.error(e);
                        aiChatHistoryService.addChatMessage(appId, e.getMessage(), ChatHistoryMessageTypeEnum.AI.getValue(),  aiApp.getAddUser());
                    }
                });
            }, FluxSink.OverflowStrategy.BUFFER);// 流量大时自动缓存
        } catch (Exception e) {
            e.printStackTrace();
            return Flux.just(e.getMessage());
        }
    }

    @Override
    public String saveApp(String message) {
        AiApp aiApp = new AiApp();
        // 应用名称暂时为 initPrompt 前 12 位
        aiApp.setAppName(message.substring(0, Math.min(message.length(), 25)));
        aiApp.setInitPrompt(message);
        // 暂时设置为多文件生成
        aiApp.setAddUser(StpUtil.getLoginIdAsString());
        aiApp.setAddTime(new Date());
        aiApp.setUpdTime(new Date());
        // 插入数据库
        boolean result = this.save(aiApp);
        if(!result){
            ResultUtils.runError("创建应用失败");
        }
        return aiApp.getId();
    }

    @Override
    public void updateShow(String appId) {
        AiApp aiApp = this.getById(appId);
        aiApp.setBShow(true);
        aiApp.setShowTime(new Date());
        boolean b = this.updateById(aiApp);
        if(!b){
            ResultUtils.runError("选为精选案例失败");
        }
        //调用事件生成网站截图
        applicationEventPublisher.publishEvent(new GenHtmlScreenshotEvent(this, appId));
    }

    @Override
    public Map<String, Object> cursorPage(String cursor,Integer size) {
        Map<String, Object> map=new HashMap<>();
        List<AiApp> list = this.list(new QueryWrapper<AiApp>()
                .lt(StrUtil.isNotBlank(cursor),"id", cursor)
                .eq("b_show", true)
                .orderByDesc("show_time")
                .last("limit "+size));
        map.put("items",list);
        // 计算下一个游标
        String nextCursor = list.isEmpty()
                ? "-1"
                : list.get(list.size() - 1).getId();
        map.put("nextCursor",nextCursor);
        map.put("length",list.isEmpty()? 0:list.size());
        return map;
    }

    @Override
    public AiApp info(String appId) {
        return this.getById(appId);
    }

}
